package utils

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/gofrs/uuid"
)

// init
// 初始化
// func init() {
// 	execPath, err := os.Executable()
// 	if err != nil {
// 		fmt.Println("get exec path error: ", err)
// 		os.Exit(1)
// 	}
// 	ExecPath = execPath
// 	LocalDir = filepath.Dir(execPath)
// }

func GetSelfPathFull() string {
	root := os.Args[0]

	// 根据相对路径获取可执行文件的绝对路径
	root, err := filepath.Abs(root)
	if err != nil {
		log.Fatalln(err)
	}

	return root
}

func GetSelfPath() string {

	return filepath.Dir(GetSelfPathFull())
}

func GetLinesFromBuffer(buf *bytes.Buffer) []string {
	var lines []string
	for _, line := range strings.Split(buf.String(), "\n") {
		line = strings.TrimSpace(line)
		if line != "" {
			lines = append(lines, line)
		}
	}
	return lines
}

func UuidGenerate() string {
	uid, err := uuid.NewV7()
	if nil != err {
		return ""
	}

	return strings.ReplaceAll(uid.String(), "-", "")
}

func IsUuid(obj interface{}) bool {
	var regUuid = regexp.MustCompile("^[0-9A-Za-z]{8}-?[0-9A-Za-z]{4}-?[0-9A-Za-z]{4}-?[0-9A-Za-z]{4}-?[0-9A-Za-z]{12}$")

	value, ok := obj.(string)
	if !ok {
		return false
	}

	ret := regUuid.MatchString(value)

	return ret
}

func RunningOs(osName ...string) string {
	if nil != osName {
		for _, name := range osName {
			sName := name
			if "macos" == sName {
				sName = "darwin"
			}
			if sName == runtime.GOOS {
				return name
			}
		}
		return ""
	}
	return runtime.GOOS
}

// 以map的key(int\float\string)排序遍历map
// eachMap      ->  待遍历的map
// eachFunc     ->  map遍历接收，入参应该符合map的key和value
// 需要对传入类型进行检查，不符合则直接panic提醒进行代码调整

func EachMapSort(eachMap interface{}, eachFunc interface{}) error {
	eachMapValue := reflect.ValueOf(eachMap)
	eachFuncValue := reflect.ValueOf(eachFunc)
	eachMapType := eachMapValue.Type()
	eachFuncType := eachFuncValue.Type()
	if eachMapValue.Kind() != reflect.Map {
		return errors.New("ksort.EachMap failed. parameter \"eachMap\" type must is map[...]...{}")
	}
	if eachFuncValue.Kind() != reflect.Func {
		return errors.New("ksort.EachMap failed. parameter \"eachFunc\" type must is func(key ..., value ...)")
	}
	if eachFuncType.NumIn() != 2 {
		return errors.New("ksort.EachMap failed. \"eachFunc\" input parameter count must is 2")
	}
	if eachFuncType.In(0).Kind() != eachMapType.Key().Kind() {
		return errors.New("ksort.EachMap failed. \"eachFunc\" input parameter 1 type not equal of \"eachMap\" key")
	}
	if eachFuncType.In(1).Kind() != eachMapType.Elem().Kind() {
		return errors.New("ksort.EachMap failed. \"eachFunc\" input parameter 2 type not equal of \"eachMap\" value")
	}

	// 对key进行排序
	// 获取排序后map的key和value，作为参数调用eachFunc即可
	switch eachMapType.Key().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		keys := make([]int, 0)
		keysMap := map[int]reflect.Value{}
		for _, value := range eachMapValue.MapKeys() {
			keys = append(keys, int(value.Int()))
			keysMap[int(value.Int())] = value
		}
		sort.Ints(keys)
		for _, key := range keys {
			eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
		}
	case reflect.Float64, reflect.Float32:
		keys := make([]float64, 0)
		keysMap := map[float64]reflect.Value{}
		for _, value := range eachMapValue.MapKeys() {
			keys = append(keys, float64(value.Float()))
			keysMap[float64(value.Float())] = value
		}
		sort.Float64s(keys)
		for _, key := range keys {
			eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
		}
	case reflect.String:
		keys := make([]string, 0)
		keysMap := map[string]reflect.Value{}
		for _, value := range eachMapValue.MapKeys() {
			keys = append(keys, value.String())
			keysMap[value.String()] = value
		}
		sort.Strings(keys)
		for _, key := range keys {
			eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
		}
	default:
		return errors.New("\"eachMap\" key type must is int or float or string")
	}
	return nil
}

func ReTry(callback func() bool, times int, step time.Duration) {
	for i := 0; i < times; i++ {
		if callback() {
			return
		}
		time.Sleep(step)
	}

}

func InterfaceToStruct(out interface{}, in interface{}) error {
	jsonStr, err := json.Marshal(in)
	if nil != err {
		return err
	}

	err = json.Unmarshal(jsonStr, &out)

	return err

}

func GetSelfIps() map[string]map[string]string {
	ips := map[string]map[string]string{
		"v4": {},
		"v6": {},
	}
	netInterfaces, err := net.Interfaces()

	if nil != err {
		return ips
	}
	v4Ips := map[string]string{}
	v6Ips := map[string]string{}
	for _, netInterface := range netInterfaces {

		netInterfaceIps, err := netInterface.Addrs()

		if nil == err {
			i := 0
			for _, addr := range netInterfaceIps {
				ipNet, isIpNet := addr.(*net.IPNet)

				//是网卡并且不是本地环回网卡
				if isIpNet && !ipNet.IP.IsLoopback() {
					ipv4 := ipNet.IP.To4()
					//能正常转成ipv4
					if ipv4 != nil {
						if _, ok := v4Ips[netInterface.Name]; ok {
							i++
							v4Ips[netInterface.Name+"."+strconv.Itoa(i)] = ipv4.String()
						} else {
							v4Ips[netInterface.Name] = ipv4.String() //addr.String() 0.0.0.0/0
						}
					} else {
						if _, ok := v6Ips[netInterface.Name]; ok {
							i++
							v6Ips[netInterface.Name+"."+strconv.Itoa(i)] = ipNet.IP.String()
						} else {
							v6Ips[netInterface.Name] = ipNet.IP.String() //addr.String() 0.0.0.0/0
						}
					}

				}

			}
		}

	}
	ips["v4"] = v4Ips
	ips["v6"] = v6Ips

	return ips
}

func GetSelfV4Ips() map[string]string {
	ips := GetSelfIps()
	if v4Ips, ok := ips["v4"]; ok {
		return v4Ips
	}

	return nil
}

func GetSelfV4IFaceFirst() string {
	ips := GetSelfV4Ips()
	for iFName, _ := range ips {
		return iFName
	}

	return ""
}
func GetSelfV4IpFirst(iFace ...string) string {
	ips := GetSelfV4Ips()
	iFaceName := ""
	if len(iFace) > 0 {
		iFaceName = iFace[0]
	}
	for iFName, ipAddr := range ips {
		if "" == iFaceName {
			return ipAddr
		} else if iFName == iFaceName {
			return ipAddr
		}
	}

	return ""
}
func GetSelfV6Ips() map[string]string {
	ips := GetSelfIps()
	if v6Ips, ok := ips["v6"]; ok {
		return v6Ips
	}

	return nil
}

func GetSelfV6IFaceFirst() string {
	ips := GetSelfV6Ips()
	for iFName, _ := range ips {
		return iFName
	}

	return ""
}

func GetSelfV6IpFirst(iFace ...string) string {
	ips := GetSelfV6Ips()
	iFaceName := ""
	if len(iFace) > 0 {
		iFaceName = iFace[0]
	}
	for iFName, ipAddr := range ips {
		if "" == iFaceName {
			return ipAddr
		} else if iFName == iFaceName {
			return ipAddr
		}
	}

	return ""
}

func GetInterfaceFiledValue(v interface{}, fieldName string) reflect.Value {
	return reflect.Indirect(reflect.ValueOf(v)).FieldByName(fieldName)
}

func MakeInstanceFromSlice(v interface{}) (i interface{}, err error) {
	typ := reflect.ValueOf(v)
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}

	if typ.Kind() != reflect.Slice {
		return nil, fmt.Errorf("argument must be a slice")
	}

	i = reflect.MakeSlice(typ.Type(), 1, 1).Index(0).Interface()

	return
}

func MapStringValues(m map[string]string) (v []string) {
	for _, s := range m {
		v = append(v, s)
	}
	return
}
